home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / cycles / sound.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  29.5 KB  |  1,150 lines

  1. /*
  2.  * sound.c                         (including aifflib by Chris Schoeneman)
  3.  *
  4.  * OK - here is the stuff specifically written for _cycles_.
  5.  * These routines are the only ones we will be calling from cycles.
  6.  * The aifflib code is at the end,  and is clearly marked,  but we don't
  7.  * need to fiddle with it.
  8.  * 
  9.  * The design of the following code is based on the sound code in _flight_
  10.  * provided with the source CD. Let me tell you straight that this is
  11.  * my first attempt at audio stuff and is a pretty lame hack, so don't get
  12.  * pissed at me if you think you can do better - just do it, be my guest.
  13.  *
  14.  * Nick Fitton 18/01/1994
  15.  * 
  16.  *          play_sound() - general routine to play an aiff soundfile.
  17.  *    play_cycle_sound() - play cycle engine note.
  18.  *   pitch_cycle_sound() - set the pitch of the cycle engine.
  19.  *     proximity_alert() - check for and play a proximity alert
  20.  *    init_sound_flags() - initialize all the flags so SFX will happen
  21.  *          init_audio() - start up the audio h/w and read the aiff's
  22.  *         close_audio() - clean up your mess boy!
  23.  */
  24.  
  25. /*
  26.  * DEL_BUF needs to be small enough to allow the pitch to change
  27.  * in real time, but large enough to provide a continous noise when
  28.  * the games slows down (machine is slow or background job starts up.
  29.  * It's a compromise, and I prefer too large... shit sound is better
  30.  * than no sound (to quote Robin Humble)
  31.  */
  32. #define DEL_BUFF 4000
  33.  
  34. #include <stdio.h>
  35. #include <stdlib.h> /* for getenv() */
  36. #include <string.h>
  37. #include <errno.h>
  38. #include <math.h>
  39. #include <audio.h>
  40. #include "cycles.h"
  41. #include "sound.h"
  42.  
  43. /*
  44.  * GLOBALS
  45.  */
  46. static ALport    outport[MAXAUDIOPORT];
  47. static char    portname[5] = "out?",
  48.         soundpath[256], *soundfileptr;
  49. static short    num_open_ports = 0;
  50. static long    cycleparams[2] = { AL_OUTPUT_RATE, AL_RATE_8000 },
  51.         oldparams[2] = { AL_OUTPUT_RATE, 0 };
  52.  
  53. static short    *audiobuf = 0;
  54.  
  55. static short    *cyclesound = 0, *pitchcycle = 0, *thrustsample;
  56. static int    cyclelength, thrustlength=0;
  57. short        sound_mode = 2;
  58.  
  59. /*
  60.  * I fork a playaiff 'coz it seems to be faster than ALwritesamps when
  61.  * im sending my channel hogging sound snippets down the wire. Maybe
  62.  * this is 'coz the parent doesn't wait for the sound to play before it
  63.  * get's on with the drawing?
  64.  */
  65. void play_sound(const char *sound)
  66. {
  67.     int pid;
  68.     char temp[128];
  69.    
  70.     if(num_open_ports == 0) return;
  71.    
  72.     /* build path name */
  73.     strcpy(soundfileptr, sound);
  74.     sprintf(temp, "/usr/sbin/playaiff %s &", soundpath);
  75.     system(temp);
  76. }
  77.  
  78. /*
  79.  * I do the cycle noise like it's done in 'flight' 'coz it's a cool way
  80.  * to interactively change the pitch while we continously dump the sound.
  81.  * BUT
  82.  * There is a catch... you have to make sure that you don't dump for too
  83.  * long at an old pitch value. This depends on the size of the buffer.
  84.  * We have a dynamic buff_thing depending on how fast the machine is running, 
  85.  * so if the machine is an Indy, or has jobs running, the sound is still
  86.  * smooth (or at least consistent with the frame rate). speed_fac is an
  87.  * average of previous frame rates then scaled. see lightcycles.c
  88.  * The result of all this is, if the machine is slow, we can keep the sound
  89.  * continous but not the pitch. If the machine is fast, we have no problems.
  90.  * Nick Fitton & Robin Humble
  91.  */
  92. void    play_cycle_sound(void)
  93. {
  94.   static int sampptr = 0;
  95.   long samplecount;
  96.   extern float speed_fac;
  97.   long buff_thing;
  98.  
  99. /* calculate our dynamic buff_thing and make sure its even so that
  100.  * both channels are always online. SFX suck if this is odd.
  101.  */
  102.   buff_thing = (long)(DEL_BUFF*speed_fac)&(~(long)1);
  103.  
  104.   if (sound_mode != 2 || thrustlength == 0) return;
  105.   while (ALgetfilled(outport[0]) < buff_thing) {
  106.     samplecount = thrustlength - sampptr;
  107.     if (samplecount <= buff_thing) {
  108. /* always send an even amount of samples to keep both channels noisy */
  109.       if(samplecount < 2) samplecount=2;
  110.       ALwritesamps(outport[0], pitchcycle+sampptr, samplecount);
  111.       sampptr = 0;
  112.     }
  113.     else {
  114.       ALwritesamps(outport[0], pitchcycle+sampptr, buff_thing);
  115.       sampptr += buff_thing;
  116.     }
  117.   }
  118. }
  119.  
  120. /* fiddle with these for a different sounding bike */
  121. #define MIN_PITCH 0.5
  122. #define MAX_PITCH 2.0
  123.  
  124. /*
  125.  * This ones a doosy. We parse 'pitch' which is a measure of the speed
  126.  * of the bike scaled between 0-1. First we rescale pitch,  so fiddle with
  127.  * the MAX_PITCH, MIN_PITCH values if you wanna change the sound.
  128.  * The idea is, as pitch increases, resample the cycle noise but only send
  129.  * every 'step'th sample at a higher volume, to increase the actual pitch
  130.  * of the sound. Make sense?
  131.  * Nick Fitton & Robin Humble
  132.  */
  133. void    pitch_cycle_sound(float pitch)
  134. {
  135.   int    i, index;
  136.   float findex, step, vol;
  137.  
  138.   if (num_open_ports == 0 || !pitchcycle) return;
  139.   play_cycle_sound();        /* avoid pauses in sound */
  140.  
  141.   pitch = (MAX_PITCH - MIN_PITCH)*pitch + MIN_PITCH;
  142.   thrustlength = cyclelength;
  143.   thrustsample = cyclesound;
  144.  
  145.   step = 0.5/pitch;
  146.   vol = (1.0 + pitch)/2.0;  /* softer than explosions */
  147.  
  148.   thrustlength = (int)((float)thrustlength * step);
  149.   thrustlength &= ~1;
  150.   step = 2.0/step;
  151.   for (findex = 0.0, i = 0; i < thrustlength; i+=2) {
  152.     index = (int)findex & ~1;
  153.     findex += step;
  154.     pitchcycle[i] = thrustsample[index] * vol;
  155.     pitchcycle[i+1] = thrustsample[index+1] * vol;
  156.   }
  157. }
  158.  
  159. static int    get_aiff_sound(char* filename, short** samplebuffer)
  160. {
  161.   AIFFfile    fd;
  162.   int        len;
  163.  
  164.   /* build path name */
  165.   strcpy(soundfileptr, filename);
  166.  
  167.   /* open file, return no length on error */
  168.   if ((fd = AIFFopen(soundpath, "r")) < 0) return 0;
  169.  
  170.   /* get size of buffer (in samples) and malloc an array */
  171.   len = AIFFgetlength(fd);
  172.   if (len <= 0) { AIFFclose(fd); return 0; }
  173.   *samplebuffer = (short*)malloc(len * 2 * sizeof(short));
  174.  
  175.   /* read the samples, close the file, return the number of samples */
  176.   len = AIFFread(fd, *samplebuffer, len);
  177.   AIFFclose(fd);
  178.   return len;
  179. }
  180.  
  181. static void    silentALerror(long errnum, const char* fmt, ...)
  182. {
  183. /* ignore all AL errors */
  184. }
  185.  
  186.  
  187. void change_cycle_pitch(float min) {
  188.     float pitch;
  189.     int i;
  190.     extern CYCLE *good, bike[CYCLES];
  191.     extern int used[CYCLES];
  192. #ifdef AUDIO
  193.     extern 
  194. #endif
  195.     short kaboom, boom[CYCLES], still_close, tumbling;
  196.  
  197. /* calculate pitch of our cycle then play the sound */
  198.     pitch = (float)(good->step - MIN_STEP)/(MAX_STEP - MIN_STEP);
  199.     if(tumbling) pitch = 0;
  200.     if(!kaboom) pitch_cycle_sound(pitch);
  201.     if(!kaboom) play_cycle_sound();
  202.  
  203. /* reset the boom flag for 'bots being restarted */
  204.     for (i = 0; i < CYCLES; i++)
  205.     if (used[i] && i != good->id && bike[i].falling < 0) boom[i] = 0;
  206.  
  207. /* sound the proximity alert if we need it */
  208. /* I dont like it, but the code is here if you want it
  209.     if (min < 0.05*DIM){
  210.     if(!still_close) play_sound("alarm.aiff");
  211.     still_close = 1;
  212.     }
  213.     else
  214.     still_close = 0;
  215. */
  216. }
  217.  
  218.  
  219. void init_sound_flags(void)
  220. {
  221.     int i;
  222. #ifdef AUDIO
  223.     extern 
  224. #endif
  225.     short kaboom, boom[CYCLES], still_close, tumbling;
  226.     
  227.     /* init sound flags */
  228.     kaboom=1;
  229.     still_close=0;
  230.     tumbling=0;
  231.     for(i=0; i<CYCLES; i++) boom[i]=0.0;
  232. }
  233.  
  234. void    init_audio(void)
  235. {
  236.   AIFFfile    fd;
  237.   ALconfig    config;
  238.   char*        path;
  239.   int        i, pathlen;
  240.  
  241.   if (num_open_ports) return;        /* return if not first call */
  242.   
  243.   /* capture errors so user doesn't see them */
  244.   ALseterrorhandler(silentALerror);
  245.  
  246.   config = ALnewconfig();
  247.   ALsetqueuesize(config, 64000);
  248.   ALsetchannels(config, AL_STEREO);
  249.   for (i = 0; i < MAXAUDIOPORT; i++) {
  250.     portname[3] = '0' + num_open_ports;
  251.     outport[num_open_ports] = ALopenport(portname, "w", config);
  252.     if (outport[num_open_ports])
  253.       if (++num_open_ports == 10)    /* ten ports max */
  254.     break;
  255.   }
  256.  
  257.   /* return if audio ports can't be opened.  if the machine
  258.    * doesn't have audio capability we'll return here */
  259.   if (num_open_ports == 0) {
  260.       /* insert lame messages to those suckers without audio here */
  261.       return;
  262.   }
  263.  
  264.   ALgetparams (AL_DEFAULT_DEVICE, oldparams, 2);
  265.   ALsetparams (AL_DEFAULT_DEVICE, cycleparams, 2);
  266.  
  267. /*
  268.  * all of this stuff is just for when we win and the game gets
  269.  * distributed with IRIX... :-)
  270.  * oh like, fer sure, in yer dreams dude....!
  271.  */
  272.   path = getenv("CYCLESOUND");
  273.  
  274.   if (!path || (pathlen = strlen(path)) > 240) { /* no path or path too long */
  275.     /* use default directory */
  276.     strcpy(soundpath, "/usr/demos/IndiZone/.data/cycles/");
  277.     soundfileptr = soundpath + strlen(soundpath);
  278.   }
  279.   else {
  280.     strcpy(soundpath, path);            /* copy path */
  281.     if (soundpath[pathlen-1] != '/')        /* only one trailing / */
  282.     soundpath[pathlen++] = '/';
  283.     soundfileptr = soundpath + pathlen;
  284.     *soundfileptr = 0;
  285.   }
  286.  
  287. /*
  288.  * read cycle noise from cycle.aiff
  289.  */
  290.   cyclelength = get_aiff_sound("cycle.aiff", &cyclesound);
  291.  
  292.   /* make buffer to hold pitch shifted cycle sound */
  293.   pitchcycle = (short*) malloc(4 * cyclelength * 2 * sizeof(short));
  294.  
  295.   if (cyclelength > 0 && !audiobuf)
  296.     audiobuf = (short*) malloc( cyclelength * 2 * sizeof( short));
  297.   else audiobuf = 0;
  298. }
  299.  
  300. void    close_audio(void)
  301. {
  302.   int i;
  303.  
  304.   ALsetparams (AL_DEFAULT_DEVICE, oldparams, 2);
  305.  
  306.   for (i = 0; i < num_open_ports; i++)
  307.     ALcloseport(outport[i]);
  308. }
  309.  
  310. /*------------------------ start of aifflib code -------------------------*/
  311. /*
  312.  * aifflib --
  313.  *
  314.  *    A library for reading and writing AIFF files
  315.  *
  316.  *        Chris Schoeneman     - 1991
  317.  *        (borrowed heavily from playaiff and recordaiff)
  318.  */
  319.  
  320. /* AIFF file typedef's and defines */
  321. typedef struct
  322. {
  323.     long samprate;
  324.     long nchannels;
  325.     long sampwidth;
  326. } audio_params_t;
  327.  
  328. typedef struct
  329. {
  330.     char id[4];
  331.     long size;
  332. } chunk_header_t;
  333.  
  334. #define CHUNK_ID     4
  335. #define CHUNK_HEADER 8
  336.  
  337. typedef struct
  338. {
  339.     chunk_header_t header;
  340.     int file_position;  /* not in AIFF file */
  341.     char type[4]; /* should contain 'AIFF' for any audio IFF file */
  342. } form_chunk_t;
  343.  
  344. #define FORM_CHUNK      12  /* including the header */ 
  345. #define FORM_CHUNK_DATA 4   
  346.  
  347. #define COMM_CHUNK      26   /* including the header */
  348. #define COMM_CHUNK_DATA 18
  349.  
  350. typedef struct
  351. {
  352.     chunk_header_t header;
  353.     int file_position;            /* not in AIFF file */
  354.     short nchannels;
  355.     unsigned long nsampframes;
  356.     short sampwidth;
  357.     long samprate;              /* not in AIFF file */
  358. } comm_chunk_t;
  359.  
  360.  
  361. #define SSND_CHUNK      16   /* including the header */
  362. #define SSND_CHUNK_DATA 8
  363.  
  364. typedef struct
  365. {
  366.     chunk_header_t header;
  367.     unsigned long offset;
  368.     unsigned long blocksize;
  369.  
  370.     long file_position; /* not in AIFF file */
  371.     long sample_bytes; /* not in AIFF file */
  372. } ssnd_chunk_t;
  373. /* end of AIFF typedef's and defines */
  374.  
  375. #define    MAXFILES    20
  376.  
  377. enum { FORM = 0, COMM = 1, SSND = 2};
  378.  
  379. #define    DEFAULT_CHANNELS    2
  380. #define    DEFAULT_WIDTH        16
  381. #define    DEFAULT_RATE        48000
  382.  
  383. static int        busy[MAXFILES],
  384.             ssnd_remaining[MAXFILES],
  385.             files = -1;
  386. static long        writepos[MAXFILES][3];
  387. static FILE*        aifffd[MAXFILES];
  388. static audio_params_t    audioparams[MAXFILES];
  389.  
  390. int        AIFFerrno;
  391. static char    *AIFFerrstr[]={
  392.             "",
  393.             "too many open files",
  394.             "cannot open file",
  395.             "invalid file id",
  396.             "invalid data size",
  397.             "invalid header",
  398.             "not an AIFF file",
  399.             "no FORM header",
  400.             "invalid chunk",
  401.             "write failure",
  402.             "audio parameters are fixed",
  403.             "unsupported number of channels",
  404.             "unsupported sample width",
  405.             "unsupported sample rate"};
  406.  
  407. static int    widthtobytes(int width);
  408. static double    ConvertFromIeeeExtended(char*);
  409. static void    ConvertToIeeeExtended(double, char*);
  410.  
  411. /*************************************************************************
  412.  **    routines to read and write the AIFF format chunks        **
  413.  *************************************************************************/
  414. /* convert bytes in big endian order to a short */
  415. static short    align_short(char* buf)
  416. {
  417.   int i;
  418.   union { unsigned char b[sizeof(short)]; short s; } align_short;
  419.  
  420.   for (i = 0; i < sizeof(short); i++) align_short.b[i] = *buf++;
  421.   return align_short.s;
  422. }
  423.  
  424. /* convert bytes in big endian order to a long */
  425. static long    align_long(char* buf)
  426. {
  427.   int i;
  428.   union { unsigned char b[sizeof(long)]; long l; } align_long;
  429.  
  430.   for (i = 0; i < sizeof(long); i++) align_long.b[i] = *buf++;
  431.   return align_long.l;
  432. }
  433.  
  434. /* convert short to bytes in big endian order */
  435. static void    short_align(char* buf, short s)
  436. {
  437.   int i;
  438.   char *scan = (char*)&s;
  439.  
  440.   for (i = 0; i < sizeof(short); i++) *buf++ = *scan++;
  441. }
  442.  
  443. /* convert long to bytes in big endian order */
  444. static void     long_align(char* buf, long l)
  445. {
  446.   int i;
  447.   char *scan = (char*)&l;
  448.  
  449.   for (i = 0; i < sizeof(long); i++) *buf++ = *scan++;
  450. }
  451.  
  452. static int      skip_chunk(AIFFfile fd, chunk_header_t* chunk_header)
  453. {
  454.   fseek(aifffd[fd], chunk_header->size, SEEK_CUR);
  455. }
  456.  
  457. static int    read_chunk_header(AIFFfile fd, chunk_header_t *chunk_header)
  458. {
  459.   char buf[CHUNK_HEADER];
  460.   int i;
  461.  
  462.   if ((i = fread(buf, 1, CHUNK_HEADER, aifffd[fd])) != CHUNK_HEADER) return i;
  463.  
  464.   for (i=0; i<4; i++) chunk_header->id[i] = buf[i];
  465.   chunk_header->size = align_long(buf+4);
  466.  
  467.   return CHUNK_HEADER;
  468. }
  469.  
  470. static int    read_form_chunk(AIFFfile fd, chunk_header_t *chunk_header,
  471.             form_chunk_t *form_data)
  472. {
  473.   char buf[FORM_CHUNK_DATA];
  474.  
  475.   if (chunk_header->size < 0) {
  476.     AIFFerrno = AIFF_BADDATASIZE;
  477.     return -1;
  478.   }
  479.   else if (chunk_header->size == 0) {
  480.     AIFFerrno = AIFF_BADDATASIZE;
  481.     return -1;
  482.   }
  483.  
  484.   if (fread(buf, 1, FORM_CHUNK_DATA, aifffd[fd]) != FORM_CHUNK_DATA) {
  485.     AIFFerrno = AIFF_BADHEADER;
  486.     return -1;
  487.   }
  488.   if (strncmp(buf, "AIFF", 4)) {
  489.     AIFFerrno = AIFF_NOTAIFF;
  490.     return -1;
  491.   }
  492.   return 0;
  493. }
  494.  
  495. static int    read_comm_chunk(AIFFfile fd, chunk_header_t *chunk_header)
  496. {
  497.   int i;
  498.   char buf[COMM_CHUNK_DATA+1];
  499.   comm_chunk_t comm_data;
  500.  
  501.   if (fread(buf, 1, COMM_CHUNK_DATA, aifffd[fd]) != COMM_CHUNK_DATA) {
  502.     AIFFerrno = AIFF_BADCHUNK;
  503.     return -1;
  504.   }
  505.  
  506.   comm_data.nchannels = align_short(buf);
  507.   comm_data.nsampframes = align_long(buf+4);
  508.   comm_data.sampwidth = align_short(buf+6);
  509.  
  510.     /*
  511.      * the sample rate value from the common chunk is an 80-bit IEEE extended
  512.      * floating point number:
  513.      * [s bit] [15 exp bits (bias=16383)] [64 mant bits (leading 1 not hidden)]
  514.      *
  515.      * turns out we can just grab bytes 2 and 3 (if bytes numbered 0 ... 9)
  516.      * and cast them as an integer: the integer value equals the sample rate
  517.      */
  518.   comm_data.samprate = (long)ConvertFromIeeeExtended(buf+8);
  519.  
  520.   audioparams[fd].samprate = comm_data.samprate;
  521.   audioparams[fd].nchannels = comm_data.nchannels;
  522.   audioparams[fd].sampwidth = comm_data.sampwidth;
  523.  
  524.   if (widthtobytes(audioparams[fd].sampwidth) == -1) {
  525.     AIFFerrno = AIFF_BADWIDTH;
  526.     audioparams[fd].sampwidth = DEFAULT_WIDTH;
  527.     return -1;
  528.   }
  529.   return 0;
  530. }
  531.  
  532. /* AIFFread calls this if there is no more sound data in the current
  533.  * SSND chunk.  It searches for the next block and sets the
  534.  * ssnd_remaining entry to the length of the block */
  535. static void    read_ssnd_chunk(AIFFfile fd)
  536. {
  537.   char buf[SSND_CHUNK_DATA];
  538.   int i;
  539.   chunk_header_t chunk_header;
  540.  
  541.   /* if no sound left, search for next SSND block */
  542.   /* NOTE: all chunks have been read through and checked for 
  543.    * validity, so we assume read_chunk_header either returns
  544.    * zero for end of file or CHUNK_HEADER for a good block */ 
  545.   while (read_chunk_header(fd, &chunk_header) != 0) {
  546.     if (!strncmp(chunk_header.id, "SSND", 4)) {
  547.       fread(buf, 1, SSND_CHUNK_DATA, aifffd[fd]);
  548.       ssnd_remaining[fd] = chunk_header.size - 2*sizeof(long);
  549.       if (ssnd_remaining[fd] != 0) break;
  550.     }
  551.     else skip_chunk(fd, &chunk_header);
  552.   }
  553. }
  554.  
  555. static int      write_form_chunk(AIFFfile fd)
  556. {
  557.   char buf[FORM_CHUNK];
  558.   int i;
  559.  
  560.   strncpy(buf, "FORM", 4);        /* form header id */
  561.   for (i=0; i<sizeof(long); i++)  /* form header size  - do later */
  562.     buf[i+4] = 0x00;
  563.   strncpy(buf+4+sizeof(long), "AIFF", 4);
  564.  
  565.   writepos[fd][FORM] = ftell(aifffd[fd]);
  566.  
  567.   if (fwrite(buf, 1, FORM_CHUNK, aifffd[fd]) != FORM_CHUNK)
  568.     { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  569.  
  570.   return 0;
  571. }
  572.  
  573. static int    write_comm_chunk(AIFFfile fd)
  574. {
  575.   char buf[COMM_CHUNK];
  576.   int i;
  577.  
  578.   strncpy(buf, "COMM", 4);            /* chunk id */
  579.   long_align(buf+4,COMM_CHUNK_DATA);        /* chunk data size */
  580.   short_align(buf+4+sizeof(long),        /* number channels */
  581.     audioparams[fd].nchannels);
  582.   long_align(buf+4+sizeof(long)+sizeof(short),    /* nsample frames */
  583.     0L);
  584.   short_align(buf+4+2*sizeof(long)+sizeof(short), /* sample width */
  585.     audioparams[fd].sampwidth);
  586.   ConvertToIeeeExtended((double)audioparams[fd].samprate, /* sample rate */
  587.     buf + 4 + 2*sizeof(long) + 2*sizeof(short));
  588.  
  589.   writepos[fd][COMM] = ftell(aifffd[fd]);
  590.  
  591.   if (fwrite(buf, 1, COMM_CHUNK, aifffd[fd]) != COMM_CHUNK)
  592.     { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  593.  
  594.   ssnd_remaining[fd] = 0;
  595.  
  596.   return 0;
  597. }
  598.  
  599. static int    write_ssnd_chunk(AIFFfile fd)
  600. {
  601.   char buf[SSND_CHUNK];
  602.   int i;
  603.  
  604.   strncpy(buf, "SSND", 4);
  605.   for (i=0; i<3*sizeof(long); i++)  /* chunk data size */
  606.     buf[i+4] = 0x00;
  607.  
  608.   writepos[fd][SSND] = ftell(aifffd[fd]);
  609.  
  610.   if (fwrite(buf, 1, SSND_CHUNK, aifffd[fd]) != SSND_CHUNK)
  611.     { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  612.  
  613.   return 0;
  614. }
  615.  
  616. static int    update_form_chunk(AIFFfile fd, long total_bytes)
  617. {
  618.   fseek(aifffd[fd], writepos[fd][FORM]+4, SEEK_SET);
  619.   total_bytes -= CHUNK_HEADER;
  620.  
  621.   if (fwrite(&total_bytes, 1, sizeof(long), aifffd[fd]) != sizeof(long))
  622.     { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  623.  
  624.   return 0;
  625. }
  626.  
  627. static int    update_comm_chunk(AIFFfile fd, long sample_frames)
  628. {
  629.   fseek(aifffd[fd], writepos[fd][COMM]+CHUNK_HEADER+sizeof(short), SEEK_SET);
  630.  
  631.   if (fwrite(&sample_frames, 1, sizeof(long), aifffd[fd]) != sizeof(long))
  632.     { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  633.  
  634.   return 0;
  635. }
  636.  
  637. static int    update_ssnd_chunk(AIFFfile fd, long sample_bytes)
  638. {
  639.   fseek(aifffd[fd], writepos[fd][SSND] + CHUNK_ID, SEEK_SET);
  640.   sample_bytes += SSND_CHUNK_DATA;
  641.  
  642.   if (fwrite(&sample_bytes, 1, sizeof(long), aifffd[fd]) != sizeof(long))
  643.     { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  644.  
  645.   return 0;
  646. }
  647.  
  648. static AIFFfile    myopen(const char* filename, const char* dir)
  649. {
  650.   int i;
  651.   FILE* fd;
  652.  
  653.   /* find first available space in table */
  654.  
  655.   for (i = 0; i < MAXFILES; i++)
  656.     if (!busy[i]) break;
  657.   if (i == MAXFILES) {
  658.     AIFFerrno = AIFF_NOMEM;
  659.     return -1;
  660.   }
  661.  
  662.   /* open file */
  663.  
  664.   fd = fopen(filename, dir);
  665.   if (!fd) {
  666.     AIFFerrno = AIFF_OPENFAILURE;
  667.     return -1;
  668.   }
  669.  
  670.   /* fill table entries */
  671.  
  672.   aifffd[i] = fd;
  673.   busy[i] = *dir;
  674.   files++;
  675.  
  676.   return (AIFFfile)i;
  677. }
  678.  
  679. static int    myclose(AIFFfile fd)
  680. {
  681.   busy[fd] = 0;
  682.   files--;
  683.   return fclose(aifffd[fd]);
  684. }
  685.  
  686. AIFFfile    AIFFopen(const char* filename, const char* dir)
  687. {
  688.   AIFFfile fd;
  689.   int n;
  690.   chunk_header_t chunk_header;
  691.   form_chunk_t form_data;
  692.  
  693.   fd = myopen(filename, dir);
  694.   if (fd < 0) return fd;
  695.  
  696.   switch (dir[0]) {
  697.     case 'r': {
  698.       chunk_header_t chunk_header;
  699.       form_chunk_t form_data;
  700.       long past_header;
  701.  
  702.       if (read_chunk_header(fd, &chunk_header) != CHUNK_HEADER) {
  703.     myclose(fd);
  704.     AIFFerrno = AIFF_BADHEADER;
  705.     return -1;
  706.       }
  707.  
  708.       if (strncmp(chunk_header.id, "FORM", 4)) {    /* form container */
  709.     AIFFerrno = AIFF_NOFORMCHUNK;
  710.     myclose(fd);
  711.     return -1;
  712.       }
  713.  
  714.       if (read_form_chunk(fd, &chunk_header, &form_data) < 0) {
  715.     myclose(fd);
  716.     return -1;
  717.       }
  718.  
  719.       /* remember where interesting stuff starts */
  720.  
  721.       past_header = ftell(aifffd[fd]);
  722.  
  723.       /* search for last COMM chunk */
  724.  
  725.       while ((n = read_chunk_header(fd, &chunk_header)) != 0) {
  726.     if (n == CHUNK_HEADER) {
  727.       if (!strncmp(chunk_header.id, "COMM", 4))
  728.         read_comm_chunk(fd, &chunk_header);
  729.       else 
  730.         skip_chunk(fd, &chunk_header);
  731.     }
  732.     else {
  733.       myclose(fd);
  734.       AIFFerrno = AIFF_BADHEADER;
  735.       return -1;
  736.     }
  737.       }
  738.  
  739.       /* set file pointer to beginning of interesting stuff */
  740.  
  741.       fseek(aifffd[fd], past_header, SEEK_SET);
  742.       ssnd_remaining[fd] = 0;
  743.       break;
  744.     }
  745.     case 'w': {
  746.       /* write the form chunk */
  747.  
  748.       if (write_form_chunk(fd) < 0) {
  749.     myclose(fd);
  750.     return -1;
  751.       }
  752.  
  753.       /* set ssnd_remaining to a bogus value as a flag to write the COMM */
  754.  
  755.       ssnd_remaining[fd] = -1;
  756.  
  757.       /* set default values for audio parameters */
  758.       AIFFsetchannels(fd,0);
  759.       AIFFsetwidth(fd,0);
  760.       AIFFsetrate(fd,0);
  761.  
  762.       break;
  763.     }
  764.   }
  765.  
  766.   return fd;
  767. }
  768.  
  769. int    AIFFclose(AIFFfile fd)
  770. {
  771.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  772.     { AIFFerrno = AIFF_BADFD; return -1; }
  773.  
  774.   if (busy[fd] == 'w') {
  775.     long total = ftell(aifffd[fd]);
  776.  
  777.     if (update_form_chunk(fd, total) < 0)
  778.       goto badwrite;
  779.     total -= FORM_CHUNK + COMM_CHUNK + SSND_CHUNK;
  780.     if (update_comm_chunk(fd, total / AIFFgetchannels(fd) 
  781.         / widthtobytes(AIFFgetwidth(fd))) < 0)
  782.       goto badwrite;
  783.     if (update_ssnd_chunk(fd, total) < 0)
  784.       goto badwrite;
  785.   }
  786.  
  787.   return myclose(fd);
  788.  
  789. badwrite:
  790.   myclose(fd);
  791.   return -1;
  792. }
  793.  
  794. int    AIFFwrite(AIFFfile fd, const void* buf, unsigned nsamp)
  795. {
  796.   int bytes_written;
  797.   unsigned nbyte;
  798.  
  799.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  800.     { AIFFerrno = AIFF_BADFD; return -1; }
  801.  
  802.   /* write COMM and SSND block headers if necessary */
  803.  
  804.   if (ssnd_remaining[fd] == -1) {
  805.     if (write_comm_chunk(fd) < 0)
  806.       { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  807.     if (write_ssnd_chunk(fd) < 0)
  808.       { AIFFerrno = AIFF_WRITEFAILURE; return -1; }
  809.   }
  810.  
  811.   /* convert number of samples to number of bytes */
  812.   nbyte = nsamp * widthtobytes(audioparams[fd].sampwidth);
  813.  
  814.   bytes_written = fwrite(buf, 1, nbyte, aifffd[fd]);
  815.  
  816.   /* convert bytes to samples */
  817.   return bytes_written / widthtobytes(audioparams[fd].sampwidth);
  818. }
  819.  
  820. int    AIFFread(AIFFfile fd, void* buf, unsigned nsamp)
  821. {
  822.   int bytes_read, nbyte;
  823.  
  824.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  825.     { AIFFerrno = AIFF_BADFD; return -1; }
  826.  
  827.   /* skip to next SSND block if necessary */
  828.  
  829.   if (ssnd_remaining[fd] == 0) read_ssnd_chunk(fd);
  830.  
  831.   /* convert number samples to number bytes */
  832.   nbyte = nsamp * widthtobytes(audioparams[fd].sampwidth);
  833.  
  834.   /* get samples */
  835.   /* FIXME:  AIFFread should always attempt to fill the buffer
  836.    *        even if has to read the next SSND block to
  837.    *        do it (and the one after that, etc.) */
  838.  
  839.   if (ssnd_remaining[fd] < nbyte)
  840.     bytes_read = fread(buf, 1, ssnd_remaining[fd], aifffd[fd]);
  841.   else
  842.     bytes_read = fread(buf, 1, nbyte, aifffd[fd]);
  843.   ssnd_remaining[fd] -= bytes_read;
  844.  
  845.   /* convert bytes to samples */
  846.   return bytes_read / widthtobytes(audioparams[fd].sampwidth);
  847. }
  848.  
  849. int    AIFFgetlength(AIFFfile fd)
  850. {
  851.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  852.     { AIFFerrno = AIFF_BADFD; return -1; }
  853.  
  854.   /* skip to next SSND block if necessary */
  855.   if (ssnd_remaining[fd] == 0) read_ssnd_chunk(fd);
  856.  
  857.   return ssnd_remaining[fd] / widthtobytes(audioparams[fd].sampwidth);
  858. }
  859.  
  860. int    AIFFgetchannels(AIFFfile fd)
  861. {
  862.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  863.     { AIFFerrno = AIFF_BADFD; return -1; }
  864.  
  865.   return audioparams[fd].nchannels;
  866. }
  867.  
  868. int    AIFFgetwidth(AIFFfile fd)
  869. {
  870.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  871.     { AIFFerrno = AIFF_BADFD; return -1; }
  872.  
  873.   return audioparams[fd].sampwidth;
  874. }
  875.  
  876. int    AIFFgetrate(AIFFfile fd)
  877. {
  878.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  879.     { AIFFerrno = AIFF_BADFD; return -1; }
  880.  
  881.   return audioparams[fd].samprate;
  882. }
  883.  
  884. int    AIFFsetchannels(AIFFfile fd, int channels)
  885. {
  886.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  887.     { AIFFerrno = AIFF_BADFD; return -1; }
  888.  
  889.   /* make sure file is write and we haven't written any sound yet */
  890.  
  891.   if (ssnd_remaining[fd] != -1)
  892.     { AIFFerrno = AIFF_PARAMSFIXED; return -1; }
  893.  
  894.   if (channels == 0) channels = DEFAULT_CHANNELS;
  895.   audioparams[fd].nchannels = channels;
  896.  
  897.   return 0;
  898. }
  899.  
  900. int    AIFFsetwidth(AIFFfile fd, int width)
  901. {
  902.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  903.     { AIFFerrno = AIFF_BADFD; return -1; }
  904.  
  905.   /* make sure file is write and we haven't written any sound yet */
  906.  
  907.   if (ssnd_remaining[fd] != -1)
  908.     { AIFFerrno = AIFF_PARAMSFIXED; return -1; }
  909.  
  910.   if (width == 0) width = DEFAULT_WIDTH;
  911.   audioparams[fd].sampwidth = width;
  912.  
  913.   return 0;
  914. }
  915.  
  916. int    AIFFsetrate(AIFFfile fd, int rate)
  917. {
  918.   if (fd < 0 || fd >= MAXFILES || !busy[fd])
  919.     { AIFFerrno = AIFF_BADFD; return -1; }
  920.  
  921.   /* make sure file is write and we haven't written any sound yet */
  922.  
  923.   if (ssnd_remaining[fd] != -1)
  924.     { AIFFerrno = AIFF_PARAMSFIXED; return -1; }
  925.  
  926.   if (rate == 0) rate = DEFAULT_RATE;
  927.   audioparams[fd].samprate = rate;
  928.  
  929.   return 0;
  930. }
  931.  
  932. static int    widthtobytes(int width)
  933. {
  934.   switch (width) {
  935.     case 8: return 1;
  936.     case 16: return 2;
  937.     case 24: return 4;        /* FIXME: is this 3 or 4 */
  938.     default: return -1;
  939.   }
  940. }
  941.  
  942. int    CONVERTchannelstoAL(int channels)
  943. {
  944.   switch (channels) {
  945.     case 1: return AL_MONO;
  946.     case 2: return AL_STEREO;
  947.     default: AIFFerrno = AIFF_BADCHANNELS; return -1;
  948.   }
  949. }
  950.  
  951. int    CONVERTALtochannels(int ALchannels)
  952. {
  953.   switch (ALchannels) {
  954.     case AL_MONO: return 1;
  955.     case AL_STEREO: return 2;
  956.     default: AIFFerrno = AIFF_BADCHANNELS; return -1;
  957.   }
  958. }
  959.  
  960. int    CONVERTwidthtoAL(int width)
  961. {
  962.   switch (width) {
  963.     case 8: return AL_SAMPLE_8;
  964.     case 16: return AL_SAMPLE_16;
  965.     case 24: return AL_SAMPLE_24;
  966.     default: AIFFerrno = AIFF_BADWIDTH; return -1;
  967.   }
  968. }
  969.  
  970. int    CONVERTALtowidth(int ALwidth)
  971. {
  972.   switch (ALwidth) {
  973.     case AL_SAMPLE_8: return 8;
  974.     case AL_SAMPLE_16: return 16;
  975.     case AL_SAMPLE_24: return 24;
  976.     default: AIFFerrno = AIFF_BADWIDTH; return -1;
  977.   }
  978. }
  979.  
  980. int    CONVERTratetoAL(int rate)
  981. {
  982.   switch (rate) {
  983.     case 48000: return AL_RATE_48000;
  984.     case 44100: return AL_RATE_44100;
  985.     case 32000: return AL_RATE_32000;
  986.     case 22050: return AL_RATE_22050;
  987.     case 16000: return AL_RATE_16000;
  988.     case 11025: return AL_RATE_11025;
  989.     case 8000: return AL_RATE_8000;
  990.     default: AIFFerrno = AIFF_BADRATE; return -1;
  991.   }
  992. }
  993.  
  994. int    CONVERTALtorate(int ALrate)
  995. {
  996.   switch (ALrate) {
  997.     case AL_RATE_48000: return 48000;
  998.     case AL_RATE_44100: return 44100;
  999.     case AL_RATE_32000: return 32000;
  1000.     case AL_RATE_16000: return 16000;
  1001.     case AL_RATE_8000: return 8000;
  1002.     default: AIFFerrno = AIFF_BADRATE; return -1;
  1003.   }
  1004. }
  1005.  
  1006. void    AIFFerror(const char* s)
  1007. {
  1008.   if (s && *s) fprintf(stderr,"%s: ",s);
  1009.   fprintf(stderr,"%s\n",AIFFerrstr[-AIFFerrno]);
  1010.   AIFFerrno = 0;
  1011. }
  1012.  
  1013. char*    AIFFstrerror(int err)
  1014. {
  1015.   return AIFFerrstr[-err];
  1016. }
  1017.  
  1018. /*
  1019.  * Copyright (C) 1988-1991 Apple Computer, Inc.
  1020.  * All rights reserved.
  1021.  *
  1022.  * Machine-independent I/O routines for IEEE floating-point numbers.
  1023.  *
  1024.  * NaN's and infinities are converted to HUGE_VAL or HUGE, which
  1025.  * happens to be infinity on IEEE machines.  Unfortunately, it is
  1026.  * impossible to preserve NaN's in a machine-independent way.
  1027.  * Infinities are, however, preserved on IEEE machines.
  1028.  *
  1029.  * These routines have been tested on the following machines:
  1030.  *    Apple Macintosh, MPW 3.1 C compiler
  1031.  *    Apple Macintosh, THINK C compiler
  1032.  *    Silicon Graphics IRIS, MIPS compiler
  1033.  *    Cray X/MP and Y/MP
  1034.  *    Digital Equipment VAX
  1035.  *
  1036.  *
  1037.  * Implemented by Malcolm Slaney and Ken Turkowski.
  1038.  *
  1039.  * Malcolm Slaney contributions during 1988-1990 include big- and little-
  1040.  * endian file I/O, conversion to and from Motorola's extended 80-bit
  1041.  * floating-point format, and conversions to and from IEEE single-
  1042.  * precision floating-point format.
  1043.  *
  1044.  * In 1991, Ken Turkowski implemented the conversions to and from
  1045.  * IEEE double-precision format, added more precision to the extended
  1046.  * conversions, and accommodated conversions involving +/- infinity,
  1047.  * NaN's, and denormalized numbers.
  1048.  */
  1049. #ifndef HUGE_VAL
  1050. # define HUGE_VAL HUGE
  1051. #endif
  1052.  
  1053. # define UnsignedToFloat(u)    \
  1054.      (((double)((long)(u - 2147483647L - 1))) + 2147483648.0)
  1055. /* stuffed ...
  1056. # define FloatToUnsigned(f)  \
  1057.     ((unsigned long)(((long)(f - 2147483648.0)) + 2147483647L + 1))
  1058. */
  1059. /****************************************************************
  1060.  * Extended precision IEEE floating-point conversion routines.
  1061.  ****************************************************************/
  1062.  
  1063. static double    ConvertFromIeeeExtended(char *bytes)
  1064. {
  1065.     double    f;
  1066.     long    expon;
  1067.     unsigned long hiMant, loMant;
  1068.  
  1069.     expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF);
  1070.     hiMant    =    ((unsigned long)(bytes[2] & 0xFF) << 24)
  1071.             |    ((unsigned long)(bytes[3] & 0xFF) << 16)
  1072.             |    ((unsigned long)(bytes[4] & 0xFF) << 8)
  1073.             |    ((unsigned long)(bytes[5] & 0xFF));
  1074.     loMant    =    ((unsigned long)(bytes[6] & 0xFF) << 24)
  1075.             |    ((unsigned long)(bytes[7] & 0xFF) << 16)
  1076.             |    ((unsigned long)(bytes[8] & 0xFF) << 8)
  1077.             |    ((unsigned long)(bytes[9] & 0xFF));
  1078.  
  1079.     if (expon == 0 && hiMant == 0 && loMant == 0) {
  1080.         f = 0;
  1081.     }
  1082.     else {
  1083.         if (expon == 0x7FFF) {    /* Infinity or NaN */
  1084.             f = HUGE_VAL;
  1085.         }
  1086.         else {
  1087.             expon -= 16383;
  1088.             f  = ldexp(UnsignedToFloat(hiMant), expon-=31);
  1089.             f += ldexp(UnsignedToFloat(loMant), expon-=32);
  1090.         }
  1091.     }
  1092.  
  1093.     if (bytes[0] & 0x80)
  1094.         return -f;
  1095.     else
  1096.         return f;
  1097. }
  1098.  
  1099. static void    ConvertToIeeeExtended(double num, char *bytes)
  1100. {
  1101.     int    sign;
  1102.     int expon;
  1103.     double fMant, fsMant;
  1104.     unsigned long hiMant, loMant;
  1105.  
  1106.     if (num < 0) {
  1107.         sign = 0x8000;
  1108.         num *= -1;
  1109.     } else {
  1110.         sign = 0;
  1111.     }
  1112.  
  1113.     if (num == 0) {
  1114.         expon = 0; hiMant = 0; loMant = 0;
  1115.     }
  1116.     else {
  1117.         fMant = frexp(num, &expon);
  1118.         if ((expon > 16384) || !(fMant < 1)) {    /* Infinity or NaN */
  1119.             expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */
  1120.         }
  1121.         else {    /* Finite */
  1122.             expon += 16382;
  1123.             if (expon < 0) {    /* denormalized */
  1124.                 fMant = ldexp(fMant, expon);
  1125.                 expon = 0;
  1126.             }
  1127.             expon |= sign;
  1128.             fMant = ldexp(fMant, 32);
  1129.             fsMant = floor(fMant);
  1130. printf("aifflib: this \"FloatToUnsigned\" routine is stuffed... commented out\n");
  1131. /*            hiMant = FloatToUnsigned(fsMant); */
  1132.             fMant = ldexp(fMant - fsMant, 32);
  1133.             fsMant = floor(fMant);
  1134. /*            loMant = FloatToUnsigned(fsMant); */
  1135.         }
  1136.     }
  1137.  
  1138.     bytes[0] = expon >> 8;
  1139.     bytes[1] = expon;
  1140.     bytes[2] = hiMant >> 24;
  1141.     bytes[3] = hiMant >> 16;
  1142.     bytes[4] = hiMant >> 8;
  1143.     bytes[5] = hiMant;
  1144.     bytes[6] = loMant >> 24;
  1145.     bytes[7] = loMant >> 16;
  1146.     bytes[8] = loMant >> 8;
  1147.     bytes[9] = loMant;
  1148. }
  1149. /*-------------------------- end of aifflib code -------------------------*/
  1150.